/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.caching.properties;

import io.iec.edp.caf.caching.enums.RedisServerMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 分布式缓存配置
 *
 * @author wangyandong
 */
@ConfigurationProperties("caching-configuration")
public class RedisCacheProperties {

    private List<CacheSettingsData> redisManagers = new ArrayList<>();

    private List<CacheSetting> cacheSettings = new ArrayList<>();

    public CacheSetting getCacheConfig(String name) {
        for (CacheSetting cacheSetting : cacheSettings) {
            if (cacheSetting.getName().equals(name)) {
                return cacheSetting;
            }
        }

        return null;
    }

    public List<CacheSetting> getCacheSettings() {
        return this.cacheSettings;
    }

    public void setRedisManagers(List<CacheSettingsData> cacheSettingsDataList) {
        this.redisManagers = cacheSettingsDataList;
        this.cacheSettings = transform(redisManagers);
    }

    private List<CacheSetting> transform(List<CacheSettingsData> redisManagers) {
        List<CacheSetting> result = new ArrayList<>();
        for (CacheSettingsData cacheSettingsData : redisManagers) {
            CacheSetting cacheSetting = new CacheSetting();
            cacheSetting.setMode(RedisServerMode.getMode(cacheSettingsData.getMode()));
            cacheSetting.setName(cacheSettingsData.getName());
            cacheSetting.setPassword(cacheSettingsData.getPassword());
            switch (cacheSetting.getMode()) {
                case CLUSTER:
                    cacheSetting.setClusterNodes(toNodeList(cacheSettingsData.getNodes()));
                    cacheSetting.setMaxRedirects(cacheSettingsData.getMaxRedirects());
                    break;
                case SENTINEL:
                    cacheSetting.setClusterNodes(toNodeList(cacheSettingsData.getNodes()));
                    cacheSetting.setMaster(cacheSettingsData.getMaster());
                    break;
                case STANDALONE:
                    cacheSetting.setHost(cacheSettingsData.getHost());
                    cacheSetting.setPort(cacheSettingsData.getPort());
                    cacheSetting.setPassword(cacheSettingsData.getPassword());
                    cacheSetting.setDatabase(cacheSettingsData.getDatabase());
                    break;
            }

            result.add(cacheSetting);
        }

        return result;
    }

    private Set<RedisNode> toNodeList(List<String> clusterNodes) {
        Set<RedisNode> nodeSet = new HashSet<>();
        for (String nodeString : clusterNodes) {
            nodeSet.add(readHostAndPortFromString(nodeString));
        }

        return nodeSet;
    }

    private RedisNode readHostAndPortFromString(String hostAndPort) {
        String[] args = StringUtils.split(hostAndPort, ":");
        Assert.notNull(args, "HostAndPort need to be seperated by  ':'.");
        Assert.isTrue(args.length == 2, "Host and Port String needs to specified as host:port");
        return new RedisNode(args[0], Integer.valueOf(args[1]));
    }

}
